﻿using System;
using System.Collections.Generic;
using System.Text;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using System.IO;
using net.veekee.common.data.csv;
using System.Collections;

namespace net.veekee.common.data.excel
{
    public class ExcelFile : AFile
    {
        private Workbook workbook = null;
        private Sheet worksheet = null;

        public override bool IsValid
        {
            get
            {
                return this.workbook != null;
            }
        }

        public ExcelFile(String filename, bool append)
            : base(filename)
        {
            try
            {
                if (System.IO.File.Exists(this.fileName))
                {
                    if (append)
                    {
                        try
                        {
                            this.workbook = new HSSFWorkbook(new FileStream(this.fileName, FileMode.OpenOrCreate));
                        }
                        catch(Exception e)
                        {
                            Log.GetInstance().Debug("{0}", e.ToString());
                        }
                    }
                    if (this.workbook == null)
                    {
                        Log.GetInstance().Debug("{0} will be overwritten", this.fileName);
                        System.IO.File.Delete(this.fileName);
                    }
                }
                if (this.workbook == null)
                    this.workbook = new HSSFWorkbook();
            }
            catch (Exception e)
            {
                Log.GetInstance().Error(e.ToString());
            }
        }

        public override void SelectSheet(String sheetName)
        {
            if (! this.IsValid)
                return;
            this.worksheet = this.workbook.GetSheet(sheetName);
            if(this.worksheet == null)
                this.worksheet = this.workbook.CreateSheet(sheetName);
        }

        public override void SelectSheet(int sheetID)
        {
            if (!this.IsValid)
                return;
            if (this.workbook.NumberOfSheets <= sheetID)
            {
                if (this.workbook.NumberOfSheets == 0)
                {
                    this.worksheet = this.workbook.CreateSheet("New Sheet");
                    return;
                }
                else
                    sheetID = this.workbook.NumberOfSheets - 1;
            }
            this.worksheet = this.workbook.GetSheetAt(sheetID);
        }

        public override void LoadHeader()
        {
            try
            {
                List<Object> list = this.GetLine(0);
                this.LineNumber = 0;
                if (list == null)
                    return;
                this.header.Clear();
                int col = 0;
                list.ForEach(new Action<Object>(delegate(Object item)
                        {
                            this.header.Add(col, item.ToString());
                            col++;
                        }));
            }
            catch (Exception e)
            {
                Log.GetInstance().Error("CSV file '{0}' couldn't be loaded: {1}", this.FileName, e.ToString());
            }
        }

        public override void SetLine(ulong line, IEnumerator items)
        {
            int col = 0;
            while(items.MoveNext())
            {
                this.SetCell(line, col, items.Current.ToString());
                col++;
            }
        }

        public override List<Object> GetLine(ulong line)
        {
            List<Object> list = new List<Object>();
            for(int col = 0 ; col < 100 ; col++)
            {
                Object val = this.GetCell(line, col);
                if(val == null)
                    break;
                list.Add(val);
            }
            return list;
        }

        public override void SetCell(ulong line, int column, Object item)
        {
            if (!this.IsValid)
                return;
            if (this.worksheet == null)
            {
                Log.GetInstance().Error("Please call to the SelectSheet function before any change");
                return;
            }
            Row dataRow = this.worksheet.GetRow((int)line);
            if (dataRow == null)
                dataRow = this.worksheet.CreateRow((int)line);
            Cell currenCell = dataRow.GetCell(column);
            if (currenCell == null)
                currenCell = dataRow.CreateCell(column);
            switch (item.GetType().ToString())
            {
                case "System.Int32":
                    dataRow.GetCell(column).SetCellValue((Int32)item);
                    break;
                case "System.UInt32":
                    dataRow.GetCell(column).SetCellValue((UInt32)item);
                    break;
                case "System.Int64":
                    dataRow.GetCell(column).SetCellValue((Int64)item);
                    break;
                case "System.UInt64":
                    dataRow.GetCell(column).SetCellValue((UInt64)item);
                    break;
                case "System.String":
                default:
                    dataRow.GetCell(column).SetCellValue(item.ToString());
                    currenCell.SetCellType(CellType.STRING);
                    break;
            }
        }

        public Object GetCell(ulong line, int column)
        {
            if (!this.IsValid)
                return null;
            if (this.worksheet == null)
            {
                Log.GetInstance().Error("Please call to the SelectSheet function before any change");
                return null;
            }
            Row dataRow = this.worksheet.GetRow((int) line);
            if (dataRow == null)
                return null;
            Cell currenCell = dataRow.GetCell(column);
            if (currenCell == null)
                return null;
            switch (currenCell.CellType)
            {
                case CellType.NUMERIC:
                    return currenCell.NumericCellValue;
                case CellType.STRING:
                default:
                    return currenCell.StringCellValue;
            }
        }

        public override AnEntry Next()
        {
            AnEntry obj = new AnEntry();
            this.LineNumber++;
            List<Object> list = this.GetLine(this.LineNumber);
            if (list == null)
                return null;
            try
            {
                List<String> slist = new List<String>();
                list.ForEach(new Action<Object>(delegate(Object item)
                {
                    slist.Add(item.ToString());
                }));
                obj.Line = this.LineNumber;
                obj.Load(this.header, slist);
            }
            catch (Exception e)
            {
                Log.GetInstance().Error("{0}@{1}: {2}", this.FileName, this.LineNumber, e.ToString());
            }
            return obj;
        }

        public override void Save()
        {
            if (!this.IsValid)
                return;
            try
            {
                using (FileStream stream = new FileStream(this.fileName, FileMode.OpenOrCreate))
                {
                    this.workbook.Write(stream);
                }
            }
            catch (Exception e)
            {
                Log.GetInstance().Error("{0}: {1}", this.FileName, e.ToString());
            }
        }

        public override void Dispose()
        {
            this.Save();
            if (this.workbook != null)
                this.workbook.Dispose();
            this.workbook = null;
        }
    }
}
